﻿const getResponseText = require('./http-reqest');
const { parseString } = require('xml2js');
const url = require('url');
const { testPermission } = require('./db-worker');

const
    CAS_SERVER = 'http://ids.cdsjs.com/authserver',
    LOCAL_SERVICE = 'http://172.20.101.3:8080',
    CAS_RESPONSE = 'cas:serviceResponse',
    CAS_SUCCESS_TAG = 'cas:authenticationSuccess',
    CAS_USER = 'cas:user';

var times = 0;

const debug = require('./debug')

// test authentication
module.exports = function (req, res, next) {
    if (!req.session) {         // failed to create session
        res.status(500).end();
        return
    }
    if (req.session.uid) {      // user has logged
        //console.log(`\r\n[auth] uid(${req.session.uid}) detected!`)
        next();
        return
    }

    let originalUrl = LOCAL_SERVICE + url.parse(req.originalUrl).pathname;

    req.session.uid = '20170018';
    res.redirect(originalUrl);


    //let { user, password } = req.params;
    //if (user === 'dev' && password==='test'){
    //    req.session.uid = '20170018';
    //    res.redirect(originalUrl);
    //}

  //  res.end('not permission!');
}

// CAS authentication function
function CASAuthenticate(req, res, next) {
    if (!req.session) {         // failed to create session
        res.status(500).end();
        return
    }
    if (req.session.uid) {      // user has logged
        //console.log(`\r\n[auth] uid(${req.session.uid}) detected!`)
        next();
        return
    }
    if (!req.query || !req.query.ticket) {
        // if a none-logged request has no query(all normal requests of this app
        // have no query parameters), it should be thought as the first request 
        // of the user, so it should be redirect to CAS server for authentication
        redirectToCas(req, res);
        return
    }
    var { ticket } = req.query;
    if (!ticket.startsWith('ST-')) {
        // Again, this app self don't use query string. If a none-logged request
        // carried a none-CAS-standard ticket in query, it would be treated as 
        // illegal and redirected to unauthorized page.
        redirectTo401(res);
        return
    }

    // url to be redirect to after authenticated successfully
    let originalUrl = LOCAL_SERVICE + url.parse(req.originalUrl).pathname;
    //console.log(`\r\n[auth-url] original url:${originalUrl}`);

    // url to verify ticket using CAS server and transform to user info
    let path = `${CAS_SERVER}/serviceValidate?service=${originalUrl}&ticket=${ticket}`;
    //console.log(`=====cas path=====\r\n${path}\r\n======= cas path end =========`);

    (async () => {
        try {
            let echo = await getResponseText(path);     // get xml response from CAS server
            //console.log(`===== cas echo begin =======\r\n${echo}\r\n===== cas echo end ========`);

            let { success, uid } = await parseXmlEcho(echo);
            if (success === true) { // CAS authenticated user successfully
                // test user's authorizations in this app
                var hasPerm = await testPermission(uid);
                if (hasPerm) {
                    //console.log(`authenticate successful!`);
                    req.session.uid = uid;
                    res.redirect(originalUrl);
                    return
                }
            }
        }
        catch (err) { console.log(err) }
        // 1.(error taking place during CAS authenticating)         or
        // 2.(error accuring during parsing CAS echo)               or                     
        // 3.(fail to authenticated by CAS)                         or
        // 4.(authenticated by CAS but not authorized in this app)
        redirectTo401(res);
    })();
}
function redirectToCas(req, res) {
    var path = `${CAS_SERVER}/login?service=${encodeURIComponent(LOCAL_SERVICE + req.originalUrl)}`;
    res.redirect(path);
}
function redirectTo401(res) {
    res.redirect('/public/noperm.html');
}
function parseXmlEcho(msg) {
    return new Promise(function (resolve, reject) {
        parseString(msg, { trim: true }, (err, root) => {
            if (err) {
                console.error(`failed to parse CAS response.\n${err}`);
                reject();
                return;
            }

            let successNode = root[CAS_RESPONSE][CAS_SUCCESS_TAG],
                uid = successNode && successNode[0][CAS_USER][0];
            if (uid) {
                resolve({ success: true, uid });
            } else {
                console.log('Failed to get ticket from CAS.\n' + JSON.stringify(root));
                resolve({ success: false });
            }
        })
    })
}

